One can add a pretext to a report, this could include such things as links to a home page etc at the top of the report.
My home page Group home page

Test Report

 ├───SECTION (Introduction)
 ├───SECTION (Basics)
 ├───SECTION (Beware there be quotes)
 ├───SECTION (Grid Layouts)
 ├───SECTION (Other Containers)
 ├───SECTION (Other Simple Objects)
 ├───SECTION (Advanced Objects)
 ├───SECTION (Styling Almost Everything)
 ├───SECTION (Latex Support!)
 ├───SECTION (Saving Reports, Using Templates)
 ├───SECTION (Sections within Sections)
 │   └───SUBSECTION (Subsection)
 │       └───SUBSECTION (Subsubsection)
 └───SECTION (The End)

Introduction

Welcome to PyReports. In PyReports two main categories are containers and objects. Containers are things that contain objects. Objects are images, text, code etc things that you would want to put in your report. Containers could reports, sections, grids, folds etc. Both the containers and the objects derive from what is called a _Node giving the report a tree structure with well defined parent child relation between its containers and objects. The root of the report tree is the report container itself where as its leaves will be the objects (objects cant contain other objects and therefore can not be parents to further nodes). As you will see below, Nodes have context managers which allow to type reports easily without having to specify the parent and child relations explicitly. It will be guessed from context. So at the heart of report typing lies the _Context object in objects.py from which the _Node derives. Class methods and variables of _Context track the creation of containers and objects and establish the necessary associations between them.

Basics

With PyReports, the suggested workflow is to use contexts (i.e with statements) to create new containers. With in any context, any object that is used directly becomes attached to that container whether it be a section, grid or any other object from containers.py. As an example one can write:

with report('My Report'): # create a report
    with Section('Introduction'): # create a section
        Txt('Hello world') # put a text in that section
        with Grid(2,1): # put a grid with 2 cols and 1 row in section
            Img(path1) # put an Img in the grid
            Img(path2) # put a second Img in the grid

One can directly attach a container to a parent via statements such as

Section('Introduction', parent=report)

when needed. By the way there is a better way to display code using Cde object:


with report('My Report'): # create a report
    with Section('Introduction'): # create a section
        Txt('Hello world') # put a text in that section

        with Grid(2,1): # put a grid with 2 cols and 1 row in section
            Img(path1) # put an Img in the grid
            Img(path2) # put a second Img in the grid


When displaying text, newlines are not taken into account and long lines get wrapped (maximum of 100 px or 50% of device width which can be changed via the configuration files, see section Styling Almost everything). Empty lines do appear as they are though. So to have an empty line in your text, you do not needs to insert

manually. It will be done automatically such as the empty line that is right below this sentence.

One can also itemize text by starting the line with -, 1-,2-, 1.,2. etc such as:

-item1
-item2

or

    1-item1
    2-item2

Not that indents at the beginning of each line are managed automatically relative to the text they are in.

Codes can be displayed using Cde object which has syntax highlighting and is automatically formatted to appear as it is on the editor.

By the way you can print what the report looks like using report.summary. It will show the contets of the report up to the point of printing:

             REPORT (Test Report)
             ├───SECTION (Introduction)
             └───SECTION (Basics)
            

You can put single images using the Img tag. Images are directly embedded to the html (unless you turn that off while creating the image) so you can share your beatiful reports with your friends without having to share the images and such. You can add titles to images but more formatting requires using Grids which is explained in the Grid Layouts section.


Planescape is awesome

Beware there be quotes

When you write formatted text or code, there is some internal machinery going on to decide when to have linebreaks and this depends on where are the newline characters in text. However not every newline character could mean that there should be a newline. For instance you might be displaying a code which has a variable equated to a string that has newline in it. Therefore newlines inside quotation marks are disregarded when displaying code. This means tracking when a quote has been opened and it has been closed. We assume that all strings in code are flanked by double quotes, single quotes can be reliably parsed in a similiar way due to python`s triple quote formatted strings where newlines should be considered as they are. So consider the following cases, first wrong, second correct:


'''
Hello world.py
I am not a quote and I am not not a quote.
What am I??
'''

string1 = "hello world I am here"

string2 = '''
            Formatting inside formatting, 
                what a head ache
            '''

a = 5




           '''
           Hello world.py
           I am not a quote and I am not not a quote.
           What am I??
           '''

           string1 = 'hello world
I am here'

           string2 = '''
                       Formatting inside formatting, 
                           what a head ache
                       '''

           a = 5



Grid Layouts

By using grids within grids, you can achieve any layout your heart desires. Consider for instance the following which uses two grids, one inside the other. As with single images, you can put a title to each grid element and we have done so below to make the layout more clear.

Part 1 of Grid 1


Part 2 of Grid2
Part 1 of Grid2


Part 2 of Grid2


Part 3 of Grid2


The code used for this layout is


with Grid(2,1, end=''):
    Img(f'{dir_path}/image1.jpeg',scale=1.3)

    with Grid(1,3,end=''):
        Img(f'{dir_path}/image2.jpeg')
        Img(f'{dir_path}/image3.png',scale=0.5)
        Img(f'{dir_path}/image4.png',scale=0.5)


Other Containers

Apart from Reports, Sections and Grids, there are two other containers: Tabs and Folds.

Tabs allow you to organize objects into tabs so that you only see one of object at a time, the one whose tab is selected. As an example:


x

x

x



Apart from each item`s individual button, there is also the open all button which shows all the items at the same time (fun fact: this button is also called the Derek button. Derek hates tabulated views).

The fold allows you to hide content by folding it. It comes automatically with the Code object (which is the only object that comes with a preexisting parent). But you can put other stuff in folds too, even other containers. This is a great way to suprise your friends!











The code for such a Fold would look like:


with Fold():
    with Grid(2,1, end=''):
        Img(f'{dir_path}/image1.jpeg',scale=1.3)

        with Grid(1,3,end=''):
            Img(f'{dir_path}/image2.jpeg')
            Img(f'{dir_path}/image3.png',scale=0.5)
            Img(f'{dir_path}/image4.png',scale=0.5)


Other Simple Objects

Up until now, we have seen images, code and text as objects. There are however more. Other simple objects are links and quotes:

What are 10 good quotes?



Click here to find out!

Apart from these there are two advanced objects which deserve a section of their own: Antigenic Cartography Maps and Plotly Plots

Advanced Objects

There are two advanced objects which deserve a section of their own.

Pyreports supports adding plotly plots and antigenic cartography maps using respectively Plt and Amp (while keeping their full interactivity):



Note that these do not use iframe, instead extract the relevant data, as well as scripts and add then embed them to the report. So as with images you dont need to share individual plots or maps when sharing your lovely reports with your friends.

On the downside, with the addition of such elements, you will also be adding alot of javascripts to your report and it will be diffucult to view it as raw html.

Styling Almost Everything

There are several way to style elements of a report. Each object and container allow style inputs in their creation. For instance consider the following text:

A GORGEOUS TEXT

This was done via the following code:


Txt('A GORGEOUS TEXT', style='font-size:50px;color:red')


Note that you can change font-size of a text with the font-size input the text object but style input always takes precedence.

Finally another way to style objects globally is to look at the configuration files default.ini and user.ini. During the creation of a project, styles in default.ini and user.ini are included in the head of the project. default.ini is meant to be the factor settings where as any changes you want to do should go to user.ini and will overwrite the respective property in default.ini.

Latex Support!

No good scientific report writing program can be without tex support. And PyReports is not without one!. Any section which should contain tex formulas can be initialized with has_tex=True input so that the report will know to include the respective javascripts when compiling. Then you can write any formula to your heart's content:

$\int exp^{-x^2} dx = ?? $

In order to add latex formulas, just add any latex formula inside a text object flanked on both sides by dollar signs as you would normally in latex. Note however once latex is included in a section, two unrelated dollar signs with in the same text in any part of the report can cause issue so make sure to escape dollar signs in such cases.

Saving Reports, Using Templates

You can initialize reports via from_template function. If you often create reports with similiar initial structure such as always having certain links at the top and fixed section names, creating a template could be a good idea. Once a template (say called lab) is created it can be used in creation of a report via

with from_template('lab','a report') as report:

Templates are created via the create_template function which allows a name for the template, pretext for the report and section titles as inputs. A created template will automatically be saved in the templates folder.

An example code for creating templates is:


from PyReports import create_template

pretext = '
Link To My home page  Link to Group home page 
' create_template('example_template',pretext)


And to use the template you can follow:


from PyReports import from_template, Txt, Section

report = from_template('example_template', 'Template Report Title')

with report:
    with Section('Section 1'):
        Txt('''
            This is a template DUH.
            ''')


A template once created, is simply an empty report with some preleminary information that is saved as a json file. This brings us to saving reports. Under normal circumstances, once you are done with a report you would save it to an html via

report.to_html('test_report.html')

On the other hand, you might want to save your file as json so that it could be loaded via PyReports in other computers or by your colleagues. This is done via

report.to_json('test_report.json') report2 = from_json('test_report.json')

Once done report2 is identical to report and can be edited as required.

Sections within Sections

If you want to create a subsection within a subsection all you have to do is invoke another Section with context manager as such:


with Section('Sections within Sections'):

    Txt('''
        If you want to create a subsection within a subsection
        all you have to do is invoke another Section with context manager
        as such:
        ''')

    with Section('Subsection'):
        Txt('''
            Hello I am a subsection. My border will keep going
            on until the end of this section.
            

            ''')
        with Section('Subsubsection'):
            Txt('Hello!')




To see it in effect we also do it here:

Subsection

Hello I am a subsection. My border will keep going on until the end of this section.









Subsubsection

Hello!

The End

As we are nearing the end of the report it is probably a good idea to see again how the summary looks like:

             REPORT (Test Report)
             ├───SECTION (Introduction)
             ├───SECTION (Basics)
             ├───SECTION (Beware there be quotes)
             ├───SECTION (Grid Layouts)
             ├───SECTION (Other Containers)
             ├───SECTION (Other Simple Objects)
             ├───SECTION (Advanced Objects)
             ├───SECTION (Styling Almost Everything)
             ├───SECTION (Latex Support!)
             ├───SECTION (Saving Reports, Using Templates)
             ├───SECTION (Sections within Sections)
             │   └───SUBSECTION (Subsection)
             │       └───SUBSECTION (Subsubsection)
             └───SECTION (The End)
            

For debugging purposes you can also print it in detailed format.

             REPORT (Test Report)
             ├───SECTION (Introduction)
             │   └───TEXT
             ├───SECTION (Basics)
             │   ├───TEXT
             │   ├───TEXT
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   ├───TEXT
             │   ├───TEXT
             │   ├───TEXT
             │   └───IMAGE
             ├───SECTION (Beware there be quotes)
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   └───FOLD
             │       └───CODE
             ├───SECTION (Grid Layouts)
             │   ├───TEXT
             │   ├───GRID
             │   │   ├───IMAGE
             │   │   └───GRID
             │   │       ├───IMAGE
             │   │       ├───IMAGE
             │   │       └───IMAGE
             │   ├───TEXT
             │   └───FOLD
             │       └───CODE
             ├───SECTION (Other Containers)
             │   ├───TEXT
             │   ├───TAB
             │   │   ├───IMAGE
             │   │   ├───IMAGE
             │   │   └───IMAGE
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───GRID
             │   │       ├───IMAGE
             │   │       └───GRID
             │   │           ├───IMAGE
             │   │           ├───IMAGE
             │   │           └───IMAGE
             │   ├───TEXT
             │   └───FOLD
             │       └───CODE
             ├───SECTION (Other Simple Objects)
             │   ├───TEXT
             │   ├───GRID
             │   │   └───QUOTE
             │   ├───LINK
             │   └───TEXT
             ├───SECTION (Advanced Objects)
             │   ├───TEXT
             │   ├───PLOT
             │   ├───ACMAP
             │   └───TEXT
             ├───SECTION (Styling Almost Everything)
             │   ├───TEXT
             │   ├───TEXT
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   └───TEXT
             ├───SECTION (Latex Support!)
             │   └───TEXT
             ├───SECTION (Saving Reports, Using Templates)
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   └───TEXT
             ├───SECTION (Sections within Sections)
             │   ├───TEXT
             │   ├───FOLD
             │   │   └───CODE
             │   ├───TEXT
             │   └───SUBSECTION (Subsection)
             │       ├───TEXT
             │       └───SUBSECTION (Subsubsection)
             │           └───TEXT
             └───SECTION (The End)
                 ├───TEXT
                 ├───TEXT
                 └───TEXT
            

As you get more comfortable with report operations you can try more advanced maniplations such as removing objects from one container and putting them to another as such:


with pr.Report('Test1'):
    with pr.Section('Section1'):
        with pr.Section('Subsection1') as subsection1:
            text = pr.Txt('Lorem Ipsum')

with pr.Report('Test2') as report2:
    section2 = pr.Section('Section1', parent=report2)

text._parent = section2


Get and set attributes are constructed such that if the parent of an object is changed, it is no longer linked to the previous parent. If it is a container, then all of its children migrate with the container to the new parent`s tree. It is basically an operation identical to detaching a node and all its descendants and reattaching to another tree.